package co.yixiang.modules.quartz.task;

import co.yixiang.modules.quartz.utils.HttpClientUtils;
import co.yixiang.modules.shop.domain.YxProductBase;
import co.yixiang.modules.shop.domain.YxProductStockOut;
import co.yixiang.modules.shop.service.ProductStockOutService;
import co.yixiang.modules.shop.service.YxProductBaseService;
import co.yixiang.modules.shop.service.dto.YxProductBaseQueryCriteria;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 定时器抓取外部商品数据详情入库
 *
 * @author frq
 * @date 2020-5-15
 */
@Slf4j
@Component
public class CrawlerTimer {

    @Autowired
    private YxProductBaseService yxProductBaseService;

    @Autowired
    private ProductStockOutService productStockOutService;
    //创建线程池
    static ExecutorService threadPool = Executors.newFixedThreadPool(20);
    //创建原生阻塞队列  队列最大容量为1000


    static BlockingQueue<Map<String,String>> queue = new ArrayBlockingQueue<Map<String,String>>(1000);
    public final static ThreadLocal<Map<String,String>> resource = new ThreadLocal<Map<String,String>>();

    /**
     * 根据商品名称搜索获取京东上的商品详情
     */
    public void run() throws InterruptedException {
        log.info("根据商品名称抓取数据定时器已启动");
        YxProductBaseQueryCriteria criteria = new YxProductBaseQueryCriteria();
        criteria.setStatus(0);
        List<YxProductBase> list = yxProductBaseService.queryAll(criteria);
        if (list != null && list.size() > 0) {
            for (YxProductBase yxProductBase : list) {
                Thread.sleep(1000L);
                String name = yxProductBase.getName();//搜索商品名称
                int id = yxProductBase.getId();
                //监视队列大小的线程
//                threadPool.execute(new Runnable() {
//                    @Override
//                    public void run() {
//                        while (true) {
//                            try {
//                                Thread.sleep(1000);
//                            } catch (InterruptedException e) {
//                                e.printStackTrace();
//                            }
////                            //获得队列当前的大小
////                            int size = queue.size();
////                            System.out.println("当前队列中有" + size + "个pid");
//                        }
//                    }
//                });
                //开启10个线程去解析手机列表页获得的pids
                for (int i = 1; i <= 10; i++) {

                    threadPool.execute(new Runnable() {
                        @Override
                        public void run() {
                            while (true) {
                                //   String pid = null;
                                Map<String,String> map = new HashMap<String, String>();
                                try {
                                    //从队列中取出pid
                                    map = queue.take();
                                    resource.set(map);
                                    YxProductStockOut productStockOut = parsePid( resource.get());
                                    productStockOut.setBaseProductId(Integer.parseInt(resource.get().get("id")));
                                    productStockOut.setImage(resource.get().get("image"));
                                    //存入数据库
                                    System.out.println("开始存入数据库");
                                    productStockOutService.save(productStockOut);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    try {
                                        //出现异常则放回队列
                                        queue.put(map);
                                    } catch (InterruptedException e1) {
                                        e1.printStackTrace();
                                    }
                                }
                            }
                        }
                    });
                }
                try {
                    name = URLEncoder.encode(name, "UTF-8");

                    //京东
                    String url = "https://search.jd.com/Search?keyword=" + name + "&wq=" + name + "&enc=utf-8";
                    //  String url = "https://search.jd.com/Search?keyword="+name+"&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&stock=1&psort=3&click=0";
                    String html = HttpClientUtils.doGet(url);
                    if (html.indexOf("汪~没有找到与") < 0) {
                        parseIndex(html,String.valueOf(id));
                        // yxProductBase.setStatus(1);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //抓取完成，修改状态

                yxProductBaseService.update(yxProductBase);
            }
        } else {
            log.info("未查到到可用的商品名称进行抓取");
        }
    }

    //解析商品页面,只解析前1条数
    private static void parseIndex(String html, String id) throws IOException, InterruptedException {
        Document document = Jsoup.parse(html);
        //商品列表
        Elements elements = document.select("#J_goodsList>ul>li");

        //获得每个li的pid
        if (elements.size() > 0) {
            String pid = elements.get(0).attr("data-sku");
            String image = elements.get(0).select("div.p-img").select("a").select("img").attr("src");
            //将pid放入队列中
            Map<String,String> map = new HashMap<String, String>();
            map.put("pid",pid);
            map.put("id",id);
            map.put("image",image);
            queue.put(map);
        }

//        if (elements != null || elements.size() != 0) {
//            for (int i = 0; elements.size() > i; i++) {
//                //只取前5条数据
//                if (i > 4) {
//                    break;
//                }
//                //获得每个li的pid
//                String pid = elements.get(i).attr("data-sku");
//                //将pid放入队列中
//                queue.put(pid);
//            }
//        }
    }

    //解析每个商品的页面 获得某个商品的详细数据
    private static YxProductStockOut parsePid(Map<String,String> pMap) throws IOException {
        //拼接url 进入手机详情页
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        String pid = pMap.get("pid");
        String productUrl = "https://item.jd.com/" + pid + ".html";
        String productHtml = HttpClientUtils.doGet(productUrl);
        Document document = Jsoup.parse(productHtml);

        YxProductStockOut productStockOut = new YxProductStockOut();

        //获得手机标题
        if (document.select("div.sku-name").size() > 0) {
            String title = document.select("div.sku-name").get(0).text();
            productStockOut.setTitle(title);
        }

        //获得图片
        // String src = document.select("#spec-img").attr("data-origin");
        // product.setPicUrl(src);
        Elements elements = document.select("#spec-list>ul>li");
        StringBuffer result = new StringBuffer();
        if (elements != null || elements.size() != 0) {
            for (Element element : elements) {
                //获得每个图片的url
                String s = "https://img11.360buyimg.com/n1/s450x450_" + element.select("img").attr("data-url");
                result.append(s);
                result.append(",");

            }
        }
        productStockOut.setPicUrl(result.toString());
        productStockOut.setBaseProductId(Integer.parseInt(pMap.get("id")));

        //获得手机品牌
        String brand = document.select("#parameter-brand li").attr("title");
        productStockOut.setBrand(brand);

        //获得手机名称
        String pname = document.select("[class=parameter2 p-parameter-list] li:first-child").attr("title");
        productStockOut.setPname(pname);


        //获得手机品牌
        String place = "";
        String specs = "";
        String weight = "";
        String sales="";
        Elements detailElements = document.select("[class=parameter2 p-parameter-list]>li");
        for (Element li : detailElements) {
            if (li.text().indexOf("产地") >= 0) {
                place = li.attr("title");
            }
            if (li.text().indexOf("毛重") >= 0) {
                weight = li.attr("title");
            }
            if (li.text().indexOf("规格") >= 0) {
                specs = li.attr("title");
            }
            if (li.text().indexOf("销量") >= 0) {
                sales = li.attr("title");
            }

        }
        // System.out.println("0000"+detailElements.get(4).attr("title"));
        productStockOut.setWeight(weight);
        productStockOut.setPlace(place);
        productStockOut.setSpecs(specs);
        productStockOut.setSales(sales);

        /*  此方案无法获取到价格
            jd的价格采用异步刷新,price不在返回的html文档中,需要我们去请求价格页面
            Elements select = document.select("span[class=price J-p-" + pid + "]");
            System.out.println(select);
        */

        //拼接价格页面url 经过测试 返回Json数据  jd对IP进行了限制,加入pduid为随机数,是为了可以获取更多数据,但是依然只能爬取部分
        String priceUrl = "https://p.3.cn/prices/mgets?pduid=" + Math.random() + "&skuIds=J_" + pid;
        String priceJson = HttpClientUtils.doGet(priceUrl);
        Gson gson = new GsonBuilder().create();
        List<Map<String, String>> list = gson.fromJson(priceJson, List.class);
        String price = list.get(0).get("p");
        productStockOut.setPrice(price);
        productStockOut.setPid(pid);
        productStockOut.setAddTime(new Date());
        productStockOut.setDataSource("1");
        productStockOut.setIsDel(0);
        return productStockOut;
    }
}
